// $Id: SettingsManager.cs 67 2008-05-07 21:07:39Z nvivo $

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Xml;
using System.Xml.XPath;

namespace DBLGen
{
    /// <summary>
    /// Manages the settings for differet types of components.
    /// </summary>
    public class SettingsManager
    {
        internal List<SettingsBag> Items = new List<SettingsBag>();

        private int IndexOf(Type type, string key)
        {
            int lastIndex = Items.Count - 1;

            for (int i = 0; i <= lastIndex; i++)
            {
                SettingsBag bag = Items[i];
                if (bag.Type == type && bag.Key == key)
                    return i;
            }

            return -1;
        }

        /// <summary>
        /// Returns true if there are settings stored for this type/key pair; otherwise, false.
        /// </summary>
        public bool Contains(Type type, string key)
        {
            return IndexOf(type, key) != -1;
        }

        /// <summary>
        /// Saves the settings for a type using a specific key.
        /// </summary>
        public void Save(Type type, string key, NameValueCollection settings)
        {
            if (type == null)
                throw new ArgumentNullException("type");
            
            SettingsBag bag = new SettingsBag();
            
            bag.Type = type;
            bag.Key = key;
            bag.Settings = settings;

            int pos = IndexOf(type, key);

            if (pos >= 0)
                Items[pos] = bag;
            else
                Items.Add(bag);
        }

        /// <summary>
        /// Loads the settings for a type using a specific key.
        /// </summary>
        public NameValueCollection Load(Type type, string key)
        {
            int pos = IndexOf(type, key);

            if (pos >= 0)
                return Items[pos].Settings;
            else
                return null;
        }

        /// <summary>
        /// Deletes the settings for a type using a specific key.
        /// </summary>
        public void Delete(Type type, string key)
        {
            int pos = IndexOf(type, key);

            if (pos >= 0)
                Items.RemoveAt(pos);
        }

        internal class SettingsBag
        {
            public string Key;
            public Type Type;
            public NameValueCollection Settings;
        }

        #region Xml Persistence

        internal static SettingsManager LoadFromXml(XPathNavigator navigator)
        {
            SettingsManager sm = new SettingsManager();

            XPathNodeIterator niGroup = navigator.Select("settingGroups/settingGroup");

            while (niGroup.MoveNext())
            {
                XPathNavigator groupNav = niGroup.Current;
                XPathNodeIterator niSetting = groupNav.Select("setting");

                NameValueCollection col = new NameValueCollection();

                while (niSetting.MoveNext())
                {
                    XPathNavigator settingNav = niSetting.Current;
                    col.Add(settingNav.GetAttribute("name", String.Empty), settingNav.Value);
                }

                Type type = Type.GetType(groupNav.GetAttribute("type", String.Empty));
                string key = groupNav.GetAttribute("key", String.Empty);

                SettingsBag bag = new SettingsBag();

                bag.Type = type;
                bag.Settings = col;

                if (!String.IsNullOrEmpty(key))
                    bag.Key = key;

                sm.Items.Add(bag);
            }

            return sm;
        }

        internal void SaveToXml(XmlWriter writer)
        {
            if (Items.Count > 0)
            {
                writer.WriteStartElement("settingGroups");

                foreach (SettingsBag bag in Items)
                {
                    NameValueCollection col = bag.Settings;

                    if (col.Count > 0)
                    {
                        writer.WriteStartElement("settingGroup");

                        writer.WriteAttributeString("type", bag.Type.AssemblyQualifiedName);

                        if (!String.IsNullOrEmpty(bag.Key))
                            writer.WriteAttributeString("key", bag.Key);

                        foreach (string key in col)
                        {
                            writer.WriteStartElement("setting");
                            writer.WriteAttributeString("name", key);
                            writer.WriteCData(col[key]);
                            writer.WriteEndElement();
                        }

                        writer.WriteEndElement();
                    }
                }

                writer.WriteEndElement();
            }
        }

        #endregion

    }
}
